﻿using System;
using System.Linq;
using Portal.Logic.Creators;
using Portal.Model;
using Portal.Repository;

namespace Portal.Logic.Services
{
	/// <summary>
	/// Class <see cref="UserInfoService"/> define user info service
	/// </summary>
	public class UserInfoService : IUserInfoService
	{
		#region Fields

		private readonly IContactInfoService _contactInfoService;
		private readonly IUserInfoCreator _cretor;
		private readonly IPortalUnitOfWorkProvider _unitOfWorks;
		private readonly IUserService _userService;

		#endregion Fields

		#region .ctor

		/// <summary>
		/// Class <see cref="UserInfoProvider"/> constructor
		/// </summary>
		/// <param name="contactInfoService"></param>
		public UserInfoService(IPortalUnitOfWorkProvider unitOfWorks, IUserService userService, IContactInfoService contactInfoService, IUserInfoCreator cretor)
		{
			if (contactInfoService == null)
			{
				throw new ArgumentNullException("contactInfoService");
			}
			if (unitOfWorks == null)
			{
				throw new ArgumentNullException("unitOfWorks");
			}
			if (userService == null)
			{
				throw new ArgumentNullException("userService");
			}
			if (cretor == null)
			{
				throw new ArgumentNullException("cretor");
			}
			_unitOfWorks = unitOfWorks;
			_userService = userService;
			_cretor = cretor;
			_contactInfoService = contactInfoService;
		}

		#endregion .ctor

		#region Methods

		/// <summary>
		/// Gets user info by user
		/// </summary>
		/// <param name="user">The user.</param>
		/// <returns>
		/// User info
		/// </returns>
		public IUserInfo GetBy(IUser user)
		{
			if (user == null)
			{
				return null;
			}
			var info = _cretor.From(user);
			if (info == null)
			{
				return null;
			}

			var infos = _contactInfoService.GetUserContactInfosBy(user.Login);
			if (infos != null)
			{
				info.PrimaryPhone = infos.Where(x => x.Type == ContactInfoType.Phone && x.IsDefault).FirstOrDefault();
				info.SecondaryPhone = infos.Where(x => x.Type == ContactInfoType.Phone && !x.IsDefault).FirstOrDefault();
				info.PrimaryEmail = infos.Where(x => x.Type == ContactInfoType.Email && x.IsDefault).FirstOrDefault();
				info.SecondaryEmail = infos.Where(x => x.Type == ContactInfoType.Email && !x.IsDefault).FirstOrDefault();
			}
			return info;
		}

		/// <summary>
		/// Validates user info
		/// </summary>
		/// <param name="userInfo">The user info</param>
		/// <returns>True if valid</returns>
		public bool IsValid(IUserInfo userInfo)
		{
			if (userInfo == null)
			{
				return false;
			}

			if (!_userService.IsValid(userInfo.User))
			{
				return false;
			}

			if (!_contactInfoService.IsValid(userInfo.PrimaryEmail))
			{
				return false;
			}
			if (!_contactInfoService.IsValid(userInfo.PrimaryPhone))
			{
				return false;
			}

			return true;
		}

		/// <summary>
		/// Saves user info
		/// </summary>
		/// <param name="userInfo">The user info</param>
		public void Save(IUserInfo userInfo)
		{
			if (userInfo == null)
			{
				return;
			}

			using (var unitOfWork = _unitOfWorks.GetTransactional())
			{
				var user = _userService.AddOrUpdate(unitOfWork.UserRepository, userInfo.User);
				_contactInfoService.DeleteAllBy(unitOfWork.ContactInfoRepository, user);
				_contactInfoService.AddOrUpdate(unitOfWork.ContactInfoRepository, user, userInfo.PrimaryPhone);
				_contactInfoService.AddOrUpdate(unitOfWork.ContactInfoRepository, user, userInfo.SecondaryPhone);
				_contactInfoService.AddOrUpdate(unitOfWork.ContactInfoRepository, user, userInfo.PrimaryEmail);
				_contactInfoService.AddOrUpdate(unitOfWork.ContactInfoRepository, user, userInfo.SecondaryEmail);
				unitOfWork.Save();
			}
		}
		#endregion Methods
	}
}